package com.itheima.behavior.task;

import com.itheima.behavior.repository.BookPopularityRepository;
import com.itheima.behavior.service.UserProfileService;
import com.itheima.model.behavior.pojos.BookPopularity;
import com.itheima.model.behavior.pojos.ReadingStatistics;
import com.itheima.model.behavior.pojos.UserBehavior;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据聚合定时任务
 * 负责定期统计和更新用户画像、图书热度等数据
 */
@Component
@Slf4j
public class DataAggregationTask {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserProfileService userProfileService;

    @Autowired
    private BookPopularityRepository bookPopularityRepository;

    /**
     * 每小时执行一次：聚合数据
     * cron表达式：每小时的第0分钟执行
     */
    @Scheduled(cron = "0 0 * * * ?")
    public void aggregateDailyStatistics() {
        log.info("========== 开始执行每日数据聚合任务 ==========");
        
        try {
            LocalDate yesterday = LocalDate.now().minusDays(1);
            
            // 获取所有有行为的用户
            List<Integer> userIds = mongoTemplate.findDistinct(
                new Query(), "userId", UserBehavior.class, Integer.class);
            
            log.info("需要聚合的用户数: {}", userIds.size());
            
            int successCount = 0;
            int failCount = 0;
            
            for (Integer userId : userIds) {
                try {
                    aggregateUserDailyStats(userId, yesterday);
                    successCount++;
                } catch (Exception e) {
                    log.error("聚合用户{}的每日数据失败", userId, e);
                    failCount++;
                }
            }
            
            log.info("每日数据聚合完成: 成功={}, 失败={}", successCount, failCount);
            
        } catch (Exception e) {
            log.error("每日数据聚合任务执行失败", e);
        }
    }

    /**
     * 每30分钟执行一次：更新用户画像
     */
    @Scheduled(cron = "0 */30 * * * ?")
    public void updateUserProfiles() {
        log.info("========== 开始执行用户画像更新任务 ==========");
        
        try {
            userProfileService.batchUpdateUserProfiles();
            log.info("用户画像更新任务执行完成");
        } catch (Exception e) {
            log.error("用户画像更新任务执行失败", e);
        }
    }

    /**
     * 每30分钟执行一次：更新图书热度
     */
    @Scheduled(cron = "0 */30 * * * ?")
    public void updateBookPopularity() {
        log.info("========== 开始执行图书热度更新任务 ==========");
        
        try {
            // 获取所有有行为的图书ID
            Query query = new Query(Criteria.where("targetType").is("book"));
            List<UserBehavior> behaviors = mongoTemplate.find(query, UserBehavior.class);
            
            Set<Integer> bookIds = behaviors.stream()
                    .map(b -> {
                        try {
                            return Integer.parseInt(b.getTargetId());
                        } catch (NumberFormatException e) {
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
            
            log.info("需要更新热度的图书数: {}", bookIds.size());
            
            int successCount = 0;
            for (Integer bookId : bookIds) {
                try {
                    updateBookPopularityScore(bookId);
                    successCount++;
                } catch (Exception e) {
                    log.error("更新图书{}热度失败", bookId, e);
                }
            }
            
            log.info("图书热度更新完成: 成功更新{}本图书", successCount);
            
        } catch (Exception e) {
            log.error("图书热度更新任务执行失败", e);
        }
    }

    /**
     * 每周一凌晨3点执行：生成周报数据
     */
    @Scheduled(cron = "0 0 3 * * 1")  // 每周一凌晨3点执行
    public void generateWeeklyReport() {
        log.info("========== 开始执行周报生成任务 ==========");
        
        try {
            // 这里可以生成各种周报数据，发送通知等
            log.info("周报生成任务执行完成");
        } catch (Exception e) {
            log.error("周报生成任务执行失败", e);
        }
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 聚合用户每日统计数据
     */
    private void aggregateUserDailyStats(Integer userId, LocalDate statDate) {
        Date startTime = Date.from(statDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date endTime = Date.from(statDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
        
        Query query = new Query(Criteria.where("userId").is(userId)
                .and("createTime").gte(startTime).lt(endTime));
        
        List<UserBehavior> behaviors = mongoTemplate.find(query, UserBehavior.class);
        
        if (behaviors.isEmpty()) {
            return;
        }
        
        // 统计阅读时长
        int readingTime = behaviors.stream()
                .filter(b -> "reading".equals(b.getBehaviorType()))
                .mapToInt(b -> b.getDuration() != null ? b.getDuration() : 0)
                .sum() / 60; // 转换为分钟
        
        // 统计阅读图书数
        int booksRead = (int) behaviors.stream()
                .filter(b -> "book_view".equals(b.getBehaviorType()) || 
                             "reading".equals(b.getBehaviorType()))
                .filter(b -> "book".equals(b.getTargetType()))
                .map(UserBehavior::getTargetId)
                .distinct()
                .count();
        
        // 统计笔记数（这里需要关联笔记数据库）
        int notesCount = 0;
        
        // 统计书评数（这里需要关联书评数据库）
        int reviewsCount = 0;
        
        // 统计页面浏览数
        int pageViews = (int) behaviors.stream()
                .filter(b -> "page_view".equals(b.getBehaviorType()))
                .count();
        
        // 保存或更新统计数据
        ReadingStatistics stats = ReadingStatistics.builder()
                .userId(userId)
                .statDate(statDate)
                .readingTime(readingTime)
                .booksRead(booksRead)
                .notesCount(notesCount)
                .reviewsCount(reviewsCount)
                .pageViews(pageViews)
                .createTime(new Date())
                .build();
        
        // 检查是否已存在
        Query existQuery = new Query(Criteria.where("userId").is(userId)
                .and("statDate").is(statDate));
        
        if (mongoTemplate.exists(existQuery, ReadingStatistics.class)) {
            mongoTemplate.remove(existQuery, ReadingStatistics.class);
        }
        
        mongoTemplate.save(stats);
    }

    /**
     * 更新图书热度分数
     */
    private void updateBookPopularityScore(Integer bookId) {
        String targetId = bookId.toString();
        
        // 统计浏览次数
        long viewCount = mongoTemplate.count(
                new Query(Criteria.where("targetType").is("book")
                        .and("targetId").is(targetId)
                        .and("behaviorType").is("book_view")),
                UserBehavior.class);
        
        // 统计阅读人数
        long readingCount = mongoTemplate.findDistinct(
                new Query(Criteria.where("targetType").is("book")
                        .and("targetId").is(targetId)
                        .and("behaviorType").is("reading")),
                "userId", UserBehavior.class, Integer.class).size();
        
        // 统计点赞数
        long likeCount = mongoTemplate.count(
                new Query(Criteria.where("targetType").is("book")
                        .and("targetId").is(targetId)
                        .and("behaviorType").is("like")),
                UserBehavior.class);
        
        // 统计收藏数
        long collectCount = mongoTemplate.count(
                new Query(Criteria.where("targetType").is("book")
                        .and("targetId").is(targetId)
                        .and("behaviorType").is("collect")),
                UserBehavior.class);
        
        // 统计笔记数和书评数（需要关联其他数据库）
        int noteCount = 0;
        int reviewCount = 0;
        
        // 计算热度分数
        // 权重：浏览(0.1) + 阅读(1.0) + 点赞(2.0) + 收藏(3.0) + 笔记(2.5) + 书评(3.5)
        BigDecimal score = BigDecimal.valueOf(viewCount * 0.1)
                .add(BigDecimal.valueOf(readingCount * 1.0))
                .add(BigDecimal.valueOf(likeCount * 2.0))
                .add(BigDecimal.valueOf(collectCount * 3.0))
                .add(BigDecimal.valueOf(noteCount * 2.5))
                .add(BigDecimal.valueOf(reviewCount * 3.5))
                .setScale(2, RoundingMode.HALF_UP);
        
        // 保存或更新热度数据
        BookPopularity popularity = bookPopularityRepository.findByBookId(bookId)
                .orElse(new BookPopularity());
        
        popularity.setBookId(bookId);
        popularity.setViewCount((int) viewCount);
        popularity.setReadingCount((int) readingCount);
        popularity.setLikeCount((int) likeCount);
        popularity.setCollectCount((int) collectCount);
        popularity.setNoteCount(noteCount);
        popularity.setReviewCount(reviewCount);
        popularity.setPopularityScore(score);
        popularity.setUpdateTime(new Date());
        
        if (popularity.getCreateTime() == null) {
            popularity.setCreateTime(new Date());
        }
        
        bookPopularityRepository.save(popularity);
    }
}

